using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using NLog;

namespace DnsService.Models
{
    /// <summary>
    /// 泛域名DNS记录模型
    /// 作者：huobing
    /// </summary>
    public class WildcardDnsRecord
    {
        /// <summary>
        /// IP地址
        /// </summary>
        public string IP { get; set; } = string.Empty;
        
        /// <summary>
        /// 域名模式（支持通配符*）
        /// </summary>
        public string DomainPattern { get; set; } = string.Empty;
        
        /// <summary>
        /// 记录类型（A、PTR等）
        /// </summary>
        public string RecordType { get; set; } = "A";
        
        /// <summary>
        /// 生存时间（秒）
        /// </summary>
        public int Ttl { get; set; } = 3600;
        
        /// <summary>
        /// 是否启用
        /// </summary>
        public bool IsEnabled { get; set; } = true;
        
        /// <summary>
        /// 更新时间
        /// </summary>
        public DateTime UpdatedTime { get; set; } = DateTime.Now;
        
        /// <summary>
        /// 检查域名是否匹配模式
        /// </summary>
        /// <param name="domain">要检查的域名</param>
        /// <returns>是否匹配</returns>
        public bool IsMatch(string domain)
        {
            if (string.IsNullOrEmpty(domain) || string.IsNullOrEmpty(DomainPattern))
                return false;
                
            // 将通配符模式转换为正则表达式
            string pattern = DomainPattern
                .Replace(".", "\\.")
                .Replace("*", ".*");
                
            return Regex.IsMatch(domain, "^" + pattern + "$", RegexOptions.IgnoreCase);
        }
        
        /// <summary>
        /// 获取匹配优先级（更精确的匹配优先级更高）
        /// </summary>
        /// <param name="domain">域名</param>
        /// <returns>优先级值（越小优先级越高）</returns>
        public int GetMatchPriority(string domain)
        {
            if (!IsMatch(domain))
                return int.MaxValue;
                
            // 通配符数量越少，优先级越高
            int wildcardCount = DomainPattern.Count(c => c == '*');
            
            // 模式长度越长，优先级越高
            int patternLength = DomainPattern.Length;
            
            return wildcardCount * 1000 + (100 - patternLength);
        }
    }
    
    /// <summary>
    /// DNS记录配置管理器（支持正向/反向双文件）
    /// 作者：huobing
    /// </summary>
    public class WildcardDnsConfigManager
    {
        private readonly List<WildcardDnsRecord> _records = [];
        private readonly string _forwardConfigFilePath;
        private readonly string? _reverseConfigFilePath;
        private FileSystemWatcher? _forwardWatcher;
        private FileSystemWatcher? _reverseWatcher;
        private bool _isWatching = false;
        private int _debounceDelayMs = 100;
        private readonly Logger _logger = LogManager.GetCurrentClassLogger();
        
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="forwardConfigFilePath">正向记录配置文件路径</param>
        /// <param name="reverseConfigFilePath">反向记录配置文件路径（可选）</param>
        public WildcardDnsConfigManager(string forwardConfigFilePath, string? reverseConfigFilePath = null)
        {
            _forwardConfigFilePath = forwardConfigFilePath;
            _reverseConfigFilePath = string.IsNullOrWhiteSpace(reverseConfigFilePath) ? null : reverseConfigFilePath;
            LoadConfig();
        }

        /// <summary>
        /// 构造函数（支持监控间隔配置）
        /// </summary>
        /// <param name="forwardConfigFilePath">正向记录配置文件路径</param>
        /// <param name="reverseConfigFilePath">反向记录配置文件路径（可选）</param>
        /// <param name="watchIntervalSeconds">监控间隔（秒），用于变更事件的防抖延迟</param>
        public WildcardDnsConfigManager(string forwardConfigFilePath, string? reverseConfigFilePath, int watchIntervalSeconds)
            : this(forwardConfigFilePath, reverseConfigFilePath)
        {
            _debounceDelayMs = Math.Max(100, watchIntervalSeconds * 1000);
        }
        
        /// <summary>
        /// 加载配置文件（同时加载正向与反向文件）
        /// </summary>
        public void LoadConfig()
        {
            try
            {
                var newRecords = new List<WildcardDnsRecord>();
                
                // 加载正向记录文件
                if (File.Exists(_forwardConfigFilePath))
                {
                    var forwardLines = File.ReadAllLines(_forwardConfigFilePath);
                    foreach (var line in forwardLines)
                    {
                        if (string.IsNullOrWhiteSpace(line) || line.TrimStart().StartsWith("#"))
                            continue;
                        
                        var parts = line.Split([' ', '\t'], StringSplitOptions.RemoveEmptyEntries);
                        if (parts.Length >= 2)
                        {
                            var record = new WildcardDnsRecord
                            {
                                IP = parts[0].Trim(),
                                DomainPattern = parts[1].Trim(),
                                RecordType = parts.Length > 2 ? parts[2].Trim() : "A",
                                Ttl = parts.Length > 3 && int.TryParse(parts[3].Trim(), out int ttl) ? ttl : 3600,
                                IsEnabled = true,
                                UpdatedTime = DateTime.Now
                            };
                            newRecords.Add(record);
                        }
                    }
                }
                else
                {
                    _logger?.Info($"DNS记录配置文件不存在: {_forwardConfigFilePath}");
                }
                
                // 加载反向记录文件
                if (!string.IsNullOrWhiteSpace(_reverseConfigFilePath) && File.Exists(_reverseConfigFilePath))
                {
                    var reverseLines = File.ReadAllLines(_reverseConfigFilePath!);
                    foreach (var line in reverseLines)
                    {
                        if (string.IsNullOrWhiteSpace(line) || line.TrimStart().StartsWith("#"))
                            continue;
                        
                        var parts = line.Split([' ', '\t'], StringSplitOptions.RemoveEmptyEntries);
                        if (parts.Length >= 2)
                        {
                            var record = new WildcardDnsRecord
                            {
                                IP = parts[0].Trim(),
                                DomainPattern = parts[1].Trim(),
                                RecordType = parts.Length > 2 ? parts[2].Trim() : "PTR",
                                Ttl = parts.Length > 3 && int.TryParse(parts[3].Trim(), out int ttl) ? ttl : 3600,
                                IsEnabled = true,
                                UpdatedTime = DateTime.Now
                            };
                            newRecords.Add(record);
                        }
                    }
                }
                
                // 添加默认的反向解析记录
                newRecords.Add(new WildcardDnsRecord
                {
                    IP = "127.0.0.1",
                    DomainPattern = "localhost",
                    RecordType = "PTR",
                    Ttl = 3600,
                    IsEnabled = true
                });
                
                _records.Clear();
                _records.AddRange(newRecords);
                
                _logger?.Info($"已加载 {_records.Count} 条DNS记录配置");
            }
            catch (Exception ex)
            {
                _logger?.Error(ex, $"加载DNS记录配置文件失败: {ex.Message}");
            }
        }
        
        /// <summary>
        /// 开始监控配置文件变化（同时监控两个文件）
        /// </summary>
        public void StartWatching()
        {
            if (_isWatching) return;
            
            try
            {
                // 正向文件监控
                var forwardDir = Path.GetDirectoryName(_forwardConfigFilePath) ?? ".";
                var forwardName = Path.GetFileName(_forwardConfigFilePath);
                _forwardWatcher = new FileSystemWatcher(forwardDir, forwardName)
                {
                    NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size,
                    EnableRaisingEvents = true
                };
                _forwardWatcher.Changed += OnConfigFileChanged;
                
                // 反向文件监控（如果提供）
                if (!string.IsNullOrWhiteSpace(_reverseConfigFilePath))
                {
                    var reverseDir = Path.GetDirectoryName(_reverseConfigFilePath) ?? ".";
                    var reverseName = Path.GetFileName(_reverseConfigFilePath);
                    _reverseWatcher = new FileSystemWatcher(reverseDir, reverseName)
                    {
                        NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size,
                        EnableRaisingEvents = true
                    };
                    _reverseWatcher.Changed += OnConfigFileChanged;
                }
                
                _isWatching = true;
                _logger?.Info($"开始监控DNS记录配置文件: {_forwardConfigFilePath}{(string.IsNullOrWhiteSpace(_reverseConfigFilePath) ? string.Empty : $", {_reverseConfigFilePath}")}");
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"启动配置文件监控失败: {ex.Message}");
            }
        }
        
        /// <summary>
        /// 停止监控配置文件变化
        /// </summary>
        public void StopWatching()
        {
            if (!_isWatching) return;
            
            try
            {
                if (_forwardWatcher != null)
                {
                    _forwardWatcher.EnableRaisingEvents = false;
                    _forwardWatcher.Changed -= OnConfigFileChanged;
                    _forwardWatcher.Dispose();
                    _forwardWatcher = null;
                }
                
                if (_reverseWatcher != null)
                {
                    _reverseWatcher.EnableRaisingEvents = false;
                    _reverseWatcher.Changed -= OnConfigFileChanged;
                    _reverseWatcher.Dispose();
                    _reverseWatcher = null;
                }
                
                _isWatching = false;
                _logger?.Info("停止监控DNS记录配置文件");
            }
            catch (Exception ex)
            {
                _logger?.Error(ex, $"停止监控失败: {ex.Message}");
            }
        }
        
        /// <summary>
        /// 配置文件变化事件处理
        /// </summary>
        private void OnConfigFileChanged(object sender, FileSystemEventArgs e)
        {
            // 延迟加载以避免文件被占用（可配置防抖延迟）
            System.Threading.Thread.Sleep(_debounceDelayMs);
            _logger?.Info($"检测到DNS记录配置文件变化: {e.FullPath}");
            LoadConfig();
        }
        
        /// <summary>
        /// 根据域名查找匹配的IP地址
        /// </summary>
        /// <param name="domain">域名</param>
        /// <param name="recordType">记录类型（默认为A）</param>
        /// <returns>匹配的IP地址，未找到返回null</returns>
        public string? ResolveDomain(string domain, string recordType = "A")
        {
            var matchingRecords = _records
                .Where(r => r.IsEnabled && 
                           r.RecordType.Equals(recordType, StringComparison.OrdinalIgnoreCase) && 
                           r.IsMatch(domain))
                .OrderBy(r => r.GetMatchPriority(domain))
                .ThenBy(r => r.DomainPattern.Length) // 更精确的匹配优先
                .ToList();
                
            return matchingRecords.FirstOrDefault()?.IP;
        }
        
        /// <summary>
        /// 根据IP地址反向解析域名
        /// </summary>
        /// <param name="ip">IP地址</param>
        /// <param name="recordType">记录类型（默认为PTR）</param>
        /// <returns>匹配的域名，未找到返回null</returns>
        public string? ReverseResolve(string ip, string recordType = "PTR")
        {
            var matchingRecords = _records
                .Where(r => r.IsEnabled && 
                           r.RecordType.Equals(recordType, StringComparison.OrdinalIgnoreCase) && 
                           r.IP.Equals(ip, StringComparison.OrdinalIgnoreCase))
                .OrderBy(r => r.DomainPattern.Length) // 更短的域名优先
                .ToList();
                
            return matchingRecords.FirstOrDefault()?.DomainPattern;
        }
        
        /// <summary>
        /// 添加DNS记录
        /// </summary>
        /// <param name="ip">IP地址</param>
        /// <param name="domainPattern">域名模式</param>
        /// <param name="recordType">记录类型</param>
        /// <param name="ttl">生存时间</param>
        /// <returns>是否成功添加</returns>
        public bool AddRecord(string ip, string domainPattern, string recordType = "A", int ttl = 3600)
        {
            // 检查是否已存在相同记录
            if (_records.Any(r => r.IP == ip && r.DomainPattern == domainPattern && 
                                r.RecordType.Equals(recordType, StringComparison.OrdinalIgnoreCase)))
                return false;
                
            var record = new WildcardDnsRecord
            {
                IP = ip,
                DomainPattern = domainPattern,
                RecordType = recordType,
                Ttl = ttl,
                IsEnabled = true,
                UpdatedTime = DateTime.Now
            };
            
            _records.Add(record);
            return true;
        }
        
        /// <summary>
        /// 保存配置到文件（双文件分离保存）
        /// </summary>
        public void SaveConfig()
        {
            try
            {
                // 如果提供了反向文件路径，则分离保存
                if (!string.IsNullOrWhiteSpace(_reverseConfigFilePath))
                {
                    var forwardLines = new List<string>
                    {
                        "# DNS正向记录配置文件",
                        "# 格式：IP地址 域名模式 [记录类型] [TTL]",
                        "# 仅保存正向记录（A/AAAA）",
                        ""
                    };
                    var reverseLines = new List<string>
                    {
                        "# DNS反向记录配置文件",
                        "# 格式：IP地址 主机名 [记录类型] [TTL]",
                        "# 仅保存反向记录（PTR）",
                        ""
                    };
                    
                    foreach (var record in _records.Where(r => r.IsEnabled))
                    {
                        var ttlText = record.Ttl != 3600 ? $" {record.Ttl}" : string.Empty;
                        if (!string.Equals(record.RecordType, "PTR", StringComparison.OrdinalIgnoreCase))
                        {
                            var typeText = record.RecordType != "A" ? $" {record.RecordType}" : string.Empty;
                            forwardLines.Add($"{record.IP} {record.DomainPattern}{typeText}{ttlText}");
                        }
                        else
                        {
                            var typeText = record.RecordType != "PTR" ? $" {record.RecordType}" : string.Empty;
                            reverseLines.Add($"{record.IP} {record.DomainPattern}{typeText}{ttlText}");
                        }
                    }
                    
                    // 确保目录存在并写入
                    var fwdDir = Path.GetDirectoryName(_forwardConfigFilePath);
                    if (!string.IsNullOrEmpty(fwdDir) && !Directory.Exists(fwdDir)) Directory.CreateDirectory(fwdDir);
                    File.WriteAllLines(_forwardConfigFilePath, forwardLines);
                    
                    var revDir = Path.GetDirectoryName(_reverseConfigFilePath);
                    if (!string.IsNullOrEmpty(revDir) && !Directory.Exists(revDir)) Directory.CreateDirectory(revDir!);
                    File.WriteAllLines(_reverseConfigFilePath!, reverseLines);
                    
                    _logger?.Info($"DNS记录配置已保存到: {_forwardConfigFilePath} 和 {_reverseConfigFilePath}");
                }
                else
                {
                    // 未提供反向路径，回退为单文件保存
                    var lines = new List<string>()
                    {
                        "# DNS记录配置文件",
                        "# 格式：IP地址 域名模式 [记录类型] [TTL]",
                        "# 支持通配符 * 匹配任意子域名",
                        ""
                    };
                    
                    foreach (var record in _records.Where(r => r.IsEnabled))
                    {
                        var line = $"{record.IP} {record.DomainPattern}";
                        if (record.RecordType != "A")
                            line += $" {record.RecordType}";
                        if (record.Ttl != 3600)
                            line += $" {record.Ttl}";
                        
                        lines.Add(line);
                    }
                    
                    var dir = Path.GetDirectoryName(_forwardConfigFilePath);
                    if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) Directory.CreateDirectory(dir);
                    File.WriteAllLines(_forwardConfigFilePath, lines);
                    _logger?.Info($"DNS记录配置已保存到: {_forwardConfigFilePath}");
                }
            }
            catch (Exception ex)
            {
                _logger?.Error(ex, $"保存DNS记录配置失败: {ex.Message}");
            }
        }
        
        /// <summary>
        /// 获取所有记录
        /// </summary>
        /// <returns>记录列表</returns>
        public List<WildcardDnsRecord> GetAllRecords()
        {
            return [.. _records];
        }
    }
}